package com.javacoo.xservice.base.interceptor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StreamUtils;

import com.google.common.util.concurrent.RateLimiter;
import com.javacoo.xservice.base.BaseRequest;
import com.javacoo.xservice.base.setting.AppCoreSetting;
import com.javacoo.xservice.base.support.HttpCode;

import lombok.extern.slf4j.Slf4j;

/**
 * 请求限制
 * <p>说明:</p>
 * <li></li>
 * @author DuanYong
 * @since 2017年11月2日上午9:07:44
 */
@Slf4j
public class RequestLimitInterceptor extends BaseInterceptor {
	private static final String MSG_TOO_MANY_REQUESTS = "{\"code\": 429,\"msg\":\"Too Many Requests\"}";
	private static final String CACHEKEY_PREFIX = "reqLimit:";
	private static final String RETRY_AFTER = "Retry-After";
	private static final String RETRY_AFTER_VALUE= "2";
	//令牌桶算法，每秒允许最大并发限制
	private RateLimiter limiter; 
	//单接口访问频次策略
	private LimitFrequencyPolicy limitFrequencyPolicy;
	@Autowired
	private AppCoreSetting appCoreSetting;
	@PostConstruct
	private void init(){
		if(appCoreSetting.getReqLimitEnabled() && appCoreSetting.getReqLimitMax().intValue() > 0){
            log.info("开启每秒允许最大并发限制:{}",appCoreSetting.getReqLimitMax());
			limiter = RateLimiter.create(appCoreSetting.getReqLimitMax()); 
		}
	}
	@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
		if(appCoreSetting.getReqLimitEnabled() && limiter != null){
			if(!limiter.tryAcquire(2,TimeUnit.SECONDS)){
                log.error("请求失败409,超过每秒允许最大并发限制:{}",limiter.getRate());
				response.setStatus(HttpCode.TOO_MANY_REQUESTS.value());
				response.setHeader(RETRY_AFTER, RETRY_AFTER_VALUE);
				return false;
			}
		}
        return super.preHandle(request, response, handler);
    }
	/**
	 * 单接口访问频次策略
	 * <p>说明:</p>
	 * <li></li>
	 * @author DuanYong
	 * @since 2017年11月2日上午9:10:27
	 */
	private class LimitFrequencyPolicy{
		private int timeSecond;
		private int limit;
		public LimitFrequencyPolicy(int timeSecond, int limit) {
			super();
			this.timeSecond = timeSecond;
			this.limit = limit;
		}
	}

	private void printLog(BaseRequest p, HttpServletRequest request){
		// 接口参数必须以utf-8编码
		ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
		try {
			StreamUtils.copy(request.getInputStream(), out);
			String json = new String(out.toByteArray(), "utf-8");
            log.error("接口->{},原始请求参数:{},流水号:{}",p.getMethod(),json,p.getTransactionSn());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
